<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>
<script>
    // 自定义构造函数  
    function Cat(name, color) {
        this.name = name;
        this.color = color;
    }

    Cat.prototype.species = "Cat";
    Cat.prototype.hall = function () {
        console.log("喵喵", "老吴");
    }
    Cat.prototype.skill = function () {
        console.log("捉老鼠", "卖萌");
    }
    Cat.prototype.say = function () {
        console.log(this.name, this.color);
    }

    Object.prototype.a = 1;
    Object.prototype.b = 2;

    console.dir(Cat);

    // 原型: [[Prototype]]
    // 实例化对象上存在原型属性( [[Prototype]]),指向创建该实例化对象的构造函数的原型对象 
    // 实例化对象[[Prototype]] => 构造函数.prototype

    // 原型链:  实例化对象在查找属性和方法过程中的链式访问机制(顺着原型链访问)


    // 实例化对象访问属性和方法的顺序?
    // (1) 自己有就访问自己的 => 实例化对象自己的属性
    // (2) 自己没有,就顺着原型[[Prototype]],访问创建该实例化对象的构造函数的原型对象 
    // (3) 如果构造函数的原型对象上找不到(Cat.prototype),继续顺着原型属性找构造函数Object.prototype!
    // (4) 如果Object.prototype上找不到, 就默认返回undefined,并不在向后查找

    // Tom -> Tom.__proto__(Cat.prototype)  => Cat.prototype.__proto__(Object.prototype) => Object.prototype.__proto__(null)
    // Tom -> Cat.prototype -> Object.prototype -> null

    var Tom = new Cat("Tom", "black");
    console.log(Tom);

    // (1) 自己有就访问自己的 => 实例化对象自己的属性
    // console.log(Tom.name, Tom.color);

    //  (2) 自己没有,就顺着原型[[Prototype]],访问创建该实例化对象的构造函数的原型对象(Cat.prototype)
    // Tom.__proto__  => Cat.prototype
    // console.log(Tom.species);
    // console.log(Tom.skill);
    // console.log(Tom.hall);
    // console.log(Tom.say);
    // Tom.say();

    // (3)
    //  如果构造函数的原型对象上找不到(Cat.prototype),怎么办?
    // 分析: 构造函数的原型对象本质也是一个对象, 它是由上级构造函数Object创建
    // 证明:
    // console.log(Cat.prototype);

    // 看构造函数的原型对象 的 原型属性指向 (老版本的写法)
    // console.log(Cat.prototype.__proto__ === Object.prototype);
    // console.log(Object.getPrototypeOf(Cat.prototype) === Object.prototype);

    // 结论:如果 构造函数的原型对象上找不到(Cat.prototype),继续顺着原型属性找构造函数Object.prototype!
    // Cat.prototype.__proto__  =>  Object.prototype
    // console.log(Tom.a);
    // console.log(Tom.b);


    // (4)
    // 如果Object.prototype上也找不到想要的属性和方法,怎么办?
    // 类推法: Object.prototype本质也是一个对象, 它是由上级构造函数Object创建
    //      => Object.prototype上找不到, 继续顺着原型属性找构造函数Object.prototype!
    //      矛盾:  如果Object.prototype上找不到,会一致沿着Object.prototype查找 => 死查找
    console.log(Object.prototype);

    // 结论:  如果Object.prototype上找不到, 就默认返回undefined,并不在向后查找
    // console.log(Object.prototype.__proto__ === null);

    // console.log(Tom.abc);






</script>

</html>